package com.xbongbong.pro.service.market.statistics.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.service.market.statistics.Customer4StaticHandle;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.StaticForMarketActivityEntity;
import com.xbongbong.saas.domain.entity.StaticForUpdateDTO;
import com.xbongbong.saas.domain.entity.StaticMarketForCustomerMergeEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.dictionary.ClueStatusEnum;
import com.xbongbong.saas.model.MarketActivityForStaticModel;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @Auther: yingjianfeng
 * @Date: 2022/3/15 14:43
 * @Description:
 */
@Slf4j
@Service("customer4StaticHandle")
public class Customer4StaticHandleImpl extends AbstractMarketActivity4StaticHandle implements Customer4StaticHandle {
    @Resource
    private MarketActivityForStaticModel marketActivityForStaticModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private EsHelper esHelper;

    @Override
    public Integer type() {
        return XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode();
    }

    @Override
    @Async("staticsMarketData")
    public void add(PaasFormDataEntity paasFormDataEntity) throws XbbException {
        try {
            Long id = paasFormDataEntity.getId();
            String corpid = paasFormDataEntity.getCorpid();
            JSONObject data = paasFormDataEntity.getData();
            StaticForMarketActivityEntity addEntity = new StaticForMarketActivityEntity();
            addEntity.setCorpid(corpid);
            StaticForMarketActivityEntity updateEntity = new StaticForMarketActivityEntity();
            updateEntity.setCorpid(corpid);
            List<StaticForMarketActivityEntity> addEntitys = new ArrayList<>();
            List<StaticForMarketActivityEntity> updateEntitys = new ArrayList<>();
            List<Long> delIds = new ArrayList<>();
            JSONArray jsonArray = data.getJSONArray(CustomerManagementEnum.CLUE_ID.getAttr());
            if (CollectionsUtil.isEmpty(jsonArray)) {
                // 此条新增客户不关联线索 不处理
                return;
            }
            // 因为这儿只有线索转客户为新建才会进来 jsonArray 只会有空和只有一个clueId的情况
            StaticForMarketActivityEntity clueActivityEntity = marketActivityForStaticModel.getByClueId(jsonArray.getLong(0), corpid);
            // 正常情况下..
            if (Objects.nonNull(clueActivityEntity)) {
                if (Objects.isNull(clueActivityEntity.getCustomerId())) {
                    // 线索未关联到客户 只需更新下客户id即可
                    BeanUtil.copyProperties(clueActivityEntity, updateEntity);
                    updateEntity.setClueStatus(ClueStatusEnum.TRANSFORMED.getCode());
                    updateEntity.setCustomerId(paasFormDataEntity.getId());
                    updateEntity.setSaleStage(null);
                    updateEntity.setSaleOpportunityId(null);
                    updateEntity.setSaleMoney(null);
                    updateEntity.setContractId(null);
                    updateEntity.setContractMoney(null);
                    updateEntitys.add(updateEntity);
                } else {
                    // 感觉有点奇怪这段  按理说既然建客户的时候有关联线索id 那肯定之前线索已经创建了 且入了中间变  这段else是不可能走进来的
                    BeanUtil.copyProperties(clueActivityEntity, addEntity);
                    addEntity.setClueStatus(ClueStatusEnum.TRANSFORMED.getCode());
                    addEntity.setId(null);
                    addEntity.setCustomerId(paasFormDataEntity.getId());
                    addEntity.setSaleStage(null);
                    addEntity.setSaleOpportunityId(null);
                    addEntity.setSaleMoney(null);
                    addEntity.setContractId(null);
                    addEntity.setContractMoney(null);
                    addEntitys.add(addEntity);
                }
            } else {
                // 非正常情况下, 对应的线索有可能没有插入进去,在这里重新插入
            }
            // 插入新数据
            if (CollectionsUtil.isNotEmpty(addEntitys)) {
                marketActivityForStaticModel.insertBatch(addEntitys, corpid);
            }
            if (CollectionsUtil.isNotEmpty(updateEntitys)) {
                marketActivityForStaticModel.updateBatchForStatic(updateEntitys);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.add ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

    }

    @Override
    @Async("staticsMarketData")
    public void update(PaasFormDataEntity paasFormDataEntity) throws XbbException {
        // 中间表存的是客户id 更新不需要操作中间表
    }

    @Override
    public void updateBatch(List<StaticForUpdateDTO> list, String corpid) throws XbbException {
        // 中间表存的是客户id 更新不需要操作中间表
    }

    @Override
    @Async("staticsMarketData")
    public void deleteBatch(List<Long> idIn, String corpid, Integer del) throws XbbException {
        try {

            if (idIn.size() == 0) {
                return;
            }
            // 这个优先级最高,必须得最先处理
            List<Long> otherNeedDel = new ArrayList<>();
            List<Long> delIds = new ArrayList<>();
            List<Long> updateIds = new ArrayList<>();

            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_STATICS_MARKET_DATA;
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            // 这里暂不处理这个del条件
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
            List<StaticForMarketActivityEntity> staticList = new ArrayList<>();
            StaticForMarketActivityEntity staticForMarketActivityEntity = new StaticForMarketActivityEntity();
            long count;
            Boolean flag = false;

            if (!Objects.equals(del, DelEnum.NORMAL.getDel())) {
                boolQueryBuilder.filter(termsQuery("customerId", idIn));
                if (Objects.equals(del, DelEnum.DELETE.getDel())) {
                    boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
                }
                if (Objects.equals(del, DelEnum.REMOVE_COMPLETELY.getDel())) {
                    boolQueryBuilder.filter(termQuery("del", DelEnum.DELETE.getDel()));
                }
                // 转化成该客户的全部线索id
                Map<Long, StaticForMarketActivityEntity> entityMap = getMarketEntity(idIn, "customerId", corpid);
                // 保留一份数据
                // List<StaticForMarketActivityEntity> marketList = marketActivityForStaticModel.getEntitysForClueDeduplication(idIn.get(0), corpid);
                sourceBuilder.query(boolQueryBuilder);
                searchRequest.source(sourceBuilder);
                count = xbbElasticsearchRestTemplate.count(searchRequest, PaasFormDataEntityExt.class);
                Map<Long, Set<Long>> marketIdAndSet = new HashMap<>();
                if (count > 0) {
                    getDelIds(delIds, sourceBuilder, searchRequest, count, marketIdAndSet);
                } else {
                    return;
                }
                // 判断是否需要新建一个对应的staticMarketEntity
//                List<Long> flag2AddNewData = getFlag2AddNewData(entityMap.keySet(), count, "marketId", corpid, "marketId");
//                List<Long> flag2AddNewData = getAddNewData(corpid, entityMap, marketIdAndSet);
                // 用客户查 就只能查出一条记录的  措意直接至空  插入就行
//                if (flag2AddNewData.size() > 0) {
                // 删除客户一定得补一条到线索的数据
                    for (StaticForMarketActivityEntity entity : entityMap.values()) {
                        entity.setId(null);
                        entity.setCustomerId(null);
                        entity.setSaleOpportunityId(null);
                        entity.setSaleStage(null);
                        entity.setSaleMoney(null);
                        entity.setContractId(null);
                        entity.setContractMoney(null);
                        staticList.add(entity);
                    }
//                }
            } else {
                // 回收站还原需要将del=1的数据置回del=0
                Set<Long> tagetIds = getTagetIds(idIn, corpid, IndexTypeEnum.IDX_STATICS_MARKET_DATA, "customerId");
                // 需要删除的数据
                otherNeedDel = getNeedToDeleteId(tagetIds, corpid, "clueId");
                boolQueryBuilder.filter(termQuery("del", DelEnum.DELETE.getDel()));
                boolQueryBuilder.filter(termsQuery("customerId", idIn));
                sourceBuilder.query(boolQueryBuilder);
                searchRequest.source(sourceBuilder);
                // 将客户的del=1的数据取出来
                getDelIds(delIds, sourceBuilder, searchRequest, idIn.size());
            }
            if (otherNeedDel.size() > 0) {
                marketActivityForStaticModel.deleteBatch(otherNeedDel, corpid, DelEnum.DELETE.getDel());
            }
            if (delIds.size() > 0) {
                // 可能需要改动, listEntitys可能数量有点多
                marketActivityForStaticModel.deleteBatch(delIds, corpid, del);
            }
            if (staticList.size() > 0) {
                marketActivityForStaticModel.insertBatch(staticList, corpid);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.deleteBatch ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    @Override
    @Async("staticsMarketData")
    public void customerMerge(StaticMarketForCustomerMergeEntity staticMarketForCustomerMergeEntity) throws XbbException {
        try {
            Boolean flag = false;
            String corpid = staticMarketForCustomerMergeEntity.getCorpid();
            // 副客户id
            Long delId = staticMarketForCustomerMergeEntity.getDelId();
            // 主客户id
            Long updateId = staticMarketForCustomerMergeEntity.getUpdateId();
            // 删除线索id
            List<Long> delClueIds = staticMarketForCustomerMergeEntity.getDelClueIds();
            // 更新线索
            List<Long> updateClueIds = staticMarketForCustomerMergeEntity.getUpdateClueIds();
            // 如果是没有权限也没有值的情况,这儿就不需要处理了
            if (CollectionsUtil.isEmpty(delClueIds) && CollectionsUtil.isEmpty(updateClueIds)) {
                return;
            }
            List<StaticForMarketActivityEntity> listEntitys = new ArrayList<>();
            List<StaticForMarketActivityEntity> updateEntitys = new ArrayList<>();
            List<Long> delIds = new ArrayList<>();
            IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_STATICS_MARKET_DATA;
            BoolQueryBuilder boolQueryBuilder = getBaseBoolQueryBuilder(corpid, indexTypeEnum);
            // boolQueryBuilder.filter(termsQuery("customerId", Arrays.asList(delId, updateId)));
            // 取出对应的线索对客户, 客户对销售机会
            // 这里取巧了  这里副客户的销售机会已经合并到了主客户下
            List<PaasFormDataEntityExt> opportunity2Customer = getOpportunity2Customer(corpid, Collections.singletonList(updateId));
            // 这个得考虑到上游线索 , 下游销售机会
            // 这两条客户关联的全部数据都清空到只到线索的情况
            removeCompleteCustomer(corpid, Arrays.asList(delId, updateId));
            // 获取线索id为updateClueIds 的数据,更新customerId为udpateId, 线索为对应的销售机会
            // 要更新的线索id不为空
            if (CollectionsUtil.isNotEmpty(updateClueIds)) {
                boolQueryBuilder.filter(termsQuery("clueId", updateClueIds));
            }
            // 获取要更新线索数量
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(boolQueryBuilder);
            SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
            searchRequest.source(sourceBuilder);
            long count = xbbElasticsearchRestTemplate.count(searchRequest, StaticForMarketActivityEntity.class);
            // 手动分页
            for (int i = 0; i <= count / 100; i++) {
                PageRequest pageRequest = EsUtil.setPage(sourceBuilder, i + 1, 100);
                XbbAggregatedPage<StaticForMarketActivityEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, StaticForMarketActivityEntity.class);
                List<StaticForMarketActivityEntity> content = esEntities.getContent();
                // TODO: 2022/3/14 这里应该只会走一次 可已优化成只查一条
                for (StaticForMarketActivityEntity entity : content) {
                    if (CollectionsUtil.isNotEmpty(opportunity2Customer)) {
                        // 主客户如果存在机会，则将机会放入主客户下，重新进行插入
                        for (PaasFormDataEntityExt paasFormDataEntityExt : opportunity2Customer) {
                            StaticForMarketActivityEntity staticForMarketActivityEntity = new StaticForMarketActivityEntity();
                            BeanUtil.copyProperties(entity, staticForMarketActivityEntity);
                            JSONObject data = paasFormDataEntityExt.getData();
                            staticForMarketActivityEntity.setId(null);
                            staticForMarketActivityEntity.setDataId(null);
                            staticForMarketActivityEntity.setCustomerId(data.getLong(SalesOpportunityEnum.CUSTOMER_NAME.getAttr()));
                            staticForMarketActivityEntity.setSaleOpportunityId(paasFormDataEntityExt.getDataId());
                            staticForMarketActivityEntity.setSaleStage(data.getString(SalesOpportunityEnum.SALE_STAGE.getAttr()));
                            staticForMarketActivityEntity.setSaleMoney(data.getDouble(SalesOpportunityEnum.ESTIMATE_AMOUNT.getAttr()));
                            listEntitys.add(staticForMarketActivityEntity);
                        }
                        delIds.add(entity.getDataId());
                    } else {
                        entity.setId(entity.getDataId());
                        entity.setCustomerId(updateId);
                        updateEntitys.add(entity);
                    }
                }
            }
            // 下面是合同的逻辑
            StaticForMarketActivityEntity baseStaticForMarketActivityEntity = null;
            if (CollectionsUtil.isNotEmpty(listEntitys)) {
                baseStaticForMarketActivityEntity = listEntitys.get(0);
            } else {
                if (CollectionsUtil.isNotEmpty(updateEntitys)) {
                    baseStaticForMarketActivityEntity = updateEntitys.get(0);
                }
            }
            if(Objects.nonNull(baseStaticForMarketActivityEntity)){
                baseStaticForMarketActivityEntity.setSaleOpportunityId(null);
                baseStaticForMarketActivityEntity.setSaleStage(null);
                baseStaticForMarketActivityEntity.setSaleMoney(null);
//            Map<Long, StaticForMarketActivityEntity> linkOpportunityIdAndEntity = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//            for (StaticForMarketActivityEntity temp : listEntitys) {
//                linkOpportunityIdAndEntity.put(temp.getSaleOpportunityId(), temp);
//            }
                // fix: 2022/3/14 这里需要处理下合同
                // 查询这个客户的合同 这里是只需处理主客户的合同  因为副客户下是不允许有合同的
                List<PaasFormDataEntityExt> contractList = getContractByCustomer(corpid, updateId);
                if (CollectionsUtil.isNotEmpty(contractList)) {
                    for (PaasFormDataEntityExt contract : contractList) {
                        JSONObject contractData = contract.getData();
                        Long contractId = contract.getId();
                        // 金额
                        Double amount = contractData.getDouble(ContractEnum.AMOUNT.getAttr());
                        // 合同关联客户id
                        Long linkCustomerId = contractData.getLong(ContractEnum.LINK_CUSTOMER.getAttr());
                        if (Objects.isNull(linkCustomerId)) {
                            continue;
                        }
                        // 因为关联客户id是一定会存在的 只需判断 关联机会id是否为空即可
                        // 客户直接建合同
                        // 需要新插入一条数据
                        StaticForMarketActivityEntity staticForMarketActivityEntity = new StaticForMarketActivityEntity();
                        BeanUtil.copyProperties(baseStaticForMarketActivityEntity, staticForMarketActivityEntity);
                        staticForMarketActivityEntity.setId(null);
                        staticForMarketActivityEntity.setDataId(null);
                        staticForMarketActivityEntity.setContractId(contractId);
                        staticForMarketActivityEntity.setContractMoney(amount);
                        listEntitys.add(staticForMarketActivityEntity);
                    }
                }
            }

            if (delIds.size() > 0) {
                // 可能需要改动, listEntitys可能数量有点多
                marketActivityForStaticModel.deleteBatch(delIds, corpid, DelEnum.REMOVE_COMPLETELY.getDel());
            }
            if (listEntitys.size() > 0) {
                marketActivityForStaticModel.insertBatch(listEntitys, corpid);
            }
            if (updateEntitys.size() > 0) {
                marketActivityForStaticModel.updateBatchForStatic(updateEntitys);
            }
        } catch (XbbException e) {
            log.error("com.xbongbong.pro.service.marketActivity4Static.MarketActivity4StaticHandle.customerMerge ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    /**
     *
     * @param corpid
     * @param idIn
     * @throws XbbException
     */
    private void removeCompleteCustomer(String corpid, List<Long> idIn) throws XbbException {
        Long count;
        List<Long> delIds = new ArrayList<>();
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_STATICS_MARKET_DATA;
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        List<StaticForMarketActivityEntity> staticList = new ArrayList<>();
        StaticForMarketActivityEntity staticForMarketActivityEntity = new StaticForMarketActivityEntity();
        // 获取要删除的线索对应的marketId一份, 已备后续恢复
        Map<Long, StaticForMarketActivityEntity> entityMap = getMarketEntity(idIn, "customerId", corpid);
        boolQueryBuilder.filter(termsQuery("customerId", idIn));
        sourceBuilder.query(boolQueryBuilder);
        searchRequest.source(sourceBuilder);
        count = xbbElasticsearchRestTemplate.count(searchRequest, StaticForMarketActivityEntity.class);
        if (count > 0) {
            getDelIds(delIds, sourceBuilder, searchRequest, count);
        } else {
            return;
        }
        // 判断是否需要新建一个对应的staticMarketEntity
        List<Long> flag2AddNewData = getFlag2AddNewData(entityMap.keySet(), count, "marketId", corpid, "marketId");
        if (flag2AddNewData.size() > 0) {
            for (StaticForMarketActivityEntity entity : entityMap.values()) {
                entity.setId(null);
                entity.setCustomerId(null);
                entity.setSaleOpportunityId(null);
                entity.setSaleStage(null);
                entity.setSaleMoney(null);
                entity.setContractId(null);
                entity.setContractMoney(null);
                staticList.add(entity);
            }
        }
        if (delIds.size() > 0) {
            // 可能需要改动, listEntitys可能数量有点多
            marketActivityForStaticModel.deleteBatch(delIds, corpid, DelEnum.REMOVE_COMPLETELY.getDel());
        }
        if (staticList.size() > 0) {
            marketActivityForStaticModel.insertBatch(staticList, corpid);
        }
    }

    /**
     * 查询这个客户的合同
     * date: 2022/3/14 7:02 下午
     *
     * @param corpid:
     * @param customerId:
     * @author yingjf
     */
    private List<PaasFormDataEntityExt> getContractByCustomer(String corpid, Long customerId) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("data." + ContactEnum.CUSTOMER_NAME.getAttr(), customerId));
        boolQueryBuilder.filter(termQuery("del", 0));
        List<PaasFormDataEntityExt> contactList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTACT, boolQueryBuilder, PaasFormDataEntityExt.class, null);
        return contactList;
    }

    public List<PaasFormDataEntityExt> getOpportunity2Customer(String corpid, Collection<Long> customerIds) throws
            XbbException {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        String esAttr4Keyword = SalesOpportunityEnum.getEsAttr4Keyword(SalesOpportunityEnum.CUSTOMER_NAME);
        boolQueryBuilder.filter(termsQuery(esAttr4Keyword, customerIds));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        return esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OPPORTUNITY, boolQueryBuilder, PaasFormDataEntityExt.class, null);
    }
}

